home *** CD-ROM | disk | FTP | other *** search
/ Floppyshop 2 / Floppyshop - 2.zip / Floppyshop - 2.iso / art&graf.ix / art-3485 / art-5110 / ximg1311 / ximgview.c < prev    next >
C/C++ Source or Header  |  1995-07-06  |  22KB  |  834 lines

  1. /* Virtual screen (X)IMG-viewer (C) 1994 by Eero Tamminen. */
  2. /* No palette conversion. */
  3. /* Using Sozobon C 2.0x (short ints) you can compile this with: */
  4. /* cc -e -O -o img.prg img.c xaesfast.a xvdifast.a */
  5.  
  6. #include <stdio.h>
  7. #include <string.h>
  8. #include <osbind.h>
  9. #include <macros.h>
  10. #ifdef __GNUC__
  11. #define lalloc  malloc
  12. #include <memory.h>
  13. #include <aesbind.h>
  14. #include <vdibind.h>
  15. #endif
  16. #ifdef __SOZOBONX__
  17. #include <malloc.h>
  18. #include <xgemfast.h>
  19. #endif
  20.  
  21. #ifndef FALSE
  22. #define FALSE 0
  23. #define TRUE  !FALSE
  24. #endif
  25.  
  26. /* ------------------------------------------- */
  27. /* error codes */
  28. #define ERR_HEADER      1
  29. #define ERR_ALLOC       2
  30. #define ERR_FILE        3
  31. #define ERR_DEPACK      4
  32. #define ERR_COLOR       5
  33.  
  34. /* how many bytes one scanline can be */
  35. #define LINEBUF   2048
  36. char buf[LINEBUF];
  37.  
  38. /* some vdi arrays and global variables (work-area) etc. */
  39. short vdi_handle, work_in[11], work_out[57],
  40.       screen_planes, screen_colors, screen_w, screen_h,
  41.       normal_palette[256*3], wg_x, wg_y, wg_w, wg_h;
  42.  
  43. /* VDI <-> Device palette order conversion matrixes:
  44.  */
  45. /* Four-plane vdi-device */
  46. short vdi2dev4[] = {0,15,1,2,4,6,3,5,7,8,9,10,12,14,11,13};
  47. /* Two-plane vdi-device */
  48. short vdi2dev2[] = {0,3,1,2};
  49.  
  50. /* ------------------------------------------- */
  51. #define XIMG      0x58494D47
  52.  
  53. typedef struct IMG_HEADER
  54. {                 /* Header of GEM Image Files   */
  55.   short version;  /* Img file format version (1) */
  56.   short length;   /* Header length in words  (8) */
  57.   short planes;   /* Number of bit-planes    (1) */
  58.   short pat_len;  /* length of Patterns      (2) */
  59.   short pix_w;    /* Pixel width in 1/1000 mmm  (372)    */
  60.   short pix_h;    /* Pixel height in 1/1000 mmm (372)    */
  61.   short img_w;    /* Pixels per line (=(x+7)/8 Bytes)    */
  62.   short img_h;    /* Total number of lines               */
  63.   long  magic;    /* Contains "XIMG" if standard color   */
  64.   short paltype;  /* palette type (0 = RGB (short each)) */
  65.   short *palette; /* palette etc.                        */
  66.   char *addr;     /* Address for the depacked bit-planes */
  67. } IMG_header;
  68.  
  69. /* ------------------------------------------- */
  70. /* IMG_RSC (for phase announcement) definition */
  71.  
  72. #define DIALOG    0 /* form/dialog */
  73. #define NOTICE    1 /* BOXTEXT in tree DIALOG_TREE */
  74.  
  75. static char notice[64] = "";
  76.  
  77. static TEDINFO rs_tdi[] = {{notice, "", "", 3, 6, 0, 0x1180, 0x0, -1, 20, 1}};
  78.  
  79. static OBJECT rs_ob[] =
  80. {{-1, 1, 1, G_BOX, NONE, OUTLINED|SHADOWED, {0xFE113CL}, 2, 1, 23, 3},
  81.  {0, -1, -1, G_BOXTEXT, LASTOB, OUTLINED, {(long)&rs_tdi[0]}, 2, 1, 19, 1}};
  82.  
  83. /* number of objects to fix */
  84. #define NUM_OBS     2
  85.  
  86. /* ------------------------------------------- */
  87. /* Function prototypes. */
  88. char    *pathcut (char *path);
  89. void    fix_rsc();
  90. void    open_work();
  91. void    close_work();
  92. void    show_notice(int flag);
  93. void    show_error(int error);
  94. char   *file_name(char *path);
  95. int     depack_img(char *name, IMG_header *info);
  96. void    show_img(IMG_header *info);
  97. void    set_colors(short *palette, int colors);
  98. int     transform_img(MFDB *image, short *palette);
  99. int     dither(unsigned short **addr, long size, unsigned short width, unsigned short planes, short *palette);
  100. int     interleave(int factor, short **addr, long size, int planes);
  101. int     convert(MFDB *image, long size);
  102.  
  103. /* ------------------------------------------- */
  104. int main(int argc, char *argv[])
  105. {
  106.   IMG_header img;
  107.   static char options[96], filename[33] = "\0";
  108.   int error = 1, i = 1, button = FALSE, type;
  109.   char *path;
  110.  
  111.   img.addr = NULL;
  112.   path = buf;
  113.   appl_init();
  114.   open_work();
  115.   fix_rsc();
  116.  
  117.   while(i < argc || (argc < 2 && (strcpy(path, "*.IMG"),
  118.     fsel_exinput(path, filename, &button, "(X)IMG-Viewer v1.3")) && button))
  119.   {
  120.     /* hide mouse */
  121.     graf_mouse(M_OFF, 0);
  122.  
  123.     if(button)
  124.       strcat(pathcut(path), filename);
  125.     else
  126.       path = argv[i];
  127.  
  128.     type = strlen(path) - 4;
  129.     if(type >= 0 && (strcmp(&path[type], ".img") == 0 ||
  130.        strcmp(&path[type], ".IMG") == 0))
  131.     {
  132.       sprintf(notice, " Loading %s... ", file_name(path));
  133.       show_notice(TRUE);
  134.  
  135.       error = depack_img(path, &img);
  136.       show_notice(FALSE);
  137.  
  138.       if(error)
  139.     show_error(error);
  140.       else
  141.       {
  142.     /* exit at right button, next pic at left button */
  143.     show_img(&img);
  144.     /* not through fileselector */
  145.     if(!button)
  146.     {
  147.           sprintf(options, "[1][%s |(%d/%d)|Size: %d x %d |Bitplanes: %d |][ Prev |Quit|Next]",
  148.                   file_name(path), i, argc - 1, img.img_w, img.img_h, img.planes);
  149.           switch(form_alert(2, options))
  150.           {
  151.             case 1:
  152.               i = max(1, i - 1);
  153.               break;
  154.             case 2:
  155.               i = argc;
  156.               break;
  157.             case 3:
  158.               i = min(argc - 1, i + 1);
  159.               break;
  160.           }
  161.         }
  162.       }
  163.  
  164.       /* redraw screen below menu */
  165.       form_dial(FMD_FINISH, wg_x, wg_y, wg_w, wg_h, wg_x, wg_y, wg_w, wg_h);
  166.     }
  167.     /* enable mouse */
  168.     graf_mouse(M_ON, 0);
  169.   }
  170.   free(img.palette);
  171.   free(img.addr);
  172.  
  173.   /* restore screen and close virtual... */
  174.   close_work();
  175.   appl_exit();
  176.   return(error);
  177. }
  178.  
  179. /* cut a filename or -mask away from the filepath */
  180. char *pathcut (char *path)
  181. {
  182.   int i = 0;
  183.  
  184.   while(path[i ++] != '\0');            /* search end of string      */
  185.   while(path[-- i] != '\\' && i >= 0);  /* search path separator     */
  186.   path[++ i] = '\0';                    /* cut path from name / mask */
  187.  
  188.   return(path);
  189. }
  190.  
  191. /* fix resource co-ordinates etc. */
  192. void fix_rsc()
  193. {
  194.   int i ;
  195.   for(i = 0; i < NUM_OBS; rsrc_obfix(rs_ob, i++));
  196. }
  197.  
  198. /* open screen, set some vars, hide mouse and disable other screen update */
  199. void open_work()
  200. {
  201.   short i, idx;
  202.  
  203.   /* open virtual screen workstation (screen) */
  204.   for(i = 0; i < 10; work_in[i ++] = 1);
  205.   work_in[10] = 2;
  206.   vdi_handle = graf_handle(&i, &i, &i, &i);
  207.   v_opnvwk(work_in, &vdi_handle, work_out);
  208.   screen_colors = work_out[13];
  209.   screen_w = work_out[0];
  210.   screen_h = work_out[1];
  211.  
  212.   /* get the number of bitplanes on screen */
  213.   vq_extnd(vdi_handle, 1, work_out);
  214.   screen_planes = work_out[4];
  215.  
  216.   /* a resolution with a palette */
  217.   if(screen_planes > 0 && screen_planes < 9)
  218.     /* get current color palette */
  219.     for(i = 0; i < screen_colors; i ++)
  220.     {
  221.       /* device->vdi->device palette order */
  222.       switch(screen_planes)
  223.       {
  224.     case 2:
  225.       idx = vdi2dev2[i];
  226.       break;
  227.     case 4:
  228.       idx = vdi2dev4[i];
  229.       break;
  230.     default:
  231.       idx = i;
  232.       }
  233.       vq_color(vdi_handle, i, 0, normal_palette + idx * 3);
  234.     }
  235.  
  236.   /* Desktop work area. */
  237.   wind_get (0, WF_WORKXYWH, &wg_x, &wg_y, &wg_w, &wg_h);
  238.  
  239.   /* suspend other screen activity */
  240.   wind_update(BEG_UPDATE);
  241.   form_dial(FMD_START, wg_x, wg_y, wg_w, wg_h, wg_x, wg_y, wg_w, wg_h);
  242. }
  243.  
  244. /* enable updates, redraw screen, show mouse and close screen */
  245. void close_work()
  246. {
  247.   /* enable other screen activities */
  248.   wind_update(END_UPDATE);
  249.   v_clsvwk(vdi_handle);
  250. }
  251.  
  252. /* show and remove a notice dialog */
  253. void show_notice(int flag)
  254. {
  255.   short extent[8];
  256.   static short x, y, w, h;
  257.  
  258.   if(flag)
  259.   {
  260.     vqt_extent (vdi_handle, notice, extent);
  261.     rs_ob[DIALOG].ob_width = rs_ob[NOTICE].ob_x * 2 + extent[2];
  262.     rs_ob[NOTICE].ob_width = extent[2];
  263.     form_center(&rs_ob[DIALOG], &x, &y, &w, &h);
  264.     form_dial(FMD_START, x, y, w, h, x, y, w, h);
  265.     objc_draw(&rs_ob[DIALOG], 0, 7, x, y, w, h);
  266.   }
  267.   else
  268.   {
  269.     form_dial(FMD_FINISH, x, y, w, h, x, y, w, h);
  270.   }
  271. }
  272.  
  273. /* show error alert */
  274. void show_error(int error)
  275. {
  276.   char message[64];
  277.  
  278.   strcpy(message, "[1][");
  279.  
  280.   switch(error)
  281.   {
  282.     case ERR_FILE:
  283.       strcat(message, "File error.");
  284.       break;
  285.     case ERR_HEADER:
  286.       strcat(message, "Invalid IMG-header.");
  287.       break;
  288.     case ERR_ALLOC:
  289.       strcat(message, "Not enough memory.");
  290.       break;
  291.     case ERR_DEPACK:
  292.       strcat(message, "Depacking error.");
  293.       break;
  294.     case ERR_COLOR:
  295.       strcat(message, "Strange palette.");
  296.       break;
  297.   }
  298.   strcat(message, " ][  OK  ]");
  299.  
  300.   form_alert(1, message);
  301. }
  302.  
  303. /* get whole path, return the address of the plain name */
  304. char *file_name(char *path)
  305. {
  306.   char *name;
  307.  
  308.   name = path + strlen(path);
  309.   while(*name != '\\' && *name != '/' && name >= path)
  310.     name --;
  311.  
  312.   return(++ name);
  313. }
  314.  
  315. /* Loads & depacks IMG (0 if succeded, else error). */
  316. /* Bitplanes are one after another in address IMG_HEADER.addr. */
  317. int depack_img(char *name, IMG_header *pic)
  318. {
  319.   int   a, b, line, plane, width, word_aligned, opcode, patt_len, pal_size,
  320.     byte_repeat, patt_repeat, scan_repeat, error = FALSE;
  321.   char  pattern[16], *address, *to, *endline;
  322.   long  size;
  323.   FILE *fp;
  324.  
  325.   if((fp = fopen(name, "rb")) == NULL)
  326.     return(ERR_FILE);
  327.  
  328.   /* read header info (bw & ximg) into image structure */
  329.   fread((char *)&(pic->version), 2, 8 + 3, fp);
  330.  
  331.   /* only 2-256 color imgs */
  332.   if(pic->planes < 1 || pic->planes > 8)
  333.   {
  334.     error = ERR_COLOR;
  335.     goto end_depack;
  336.   }
  337.  
  338.   /* if XIMG, read info */
  339.   if(pic->magic == XIMG && pic->paltype == 0)
  340.   {
  341.     pal_size = (1 << pic->planes) * 3 * 2;
  342.     if((pic->palette = (short *)malloc(pal_size)))
  343.     {
  344.       fread((char *)pic->palette, 1, pal_size, fp);
  345.     }
  346.   }
  347.   else
  348.   {
  349.     pic->palette = NULL;
  350.   }
  351.  
  352.   /* width in bytes word aliged */
  353.   word_aligned = (pic->img_w + 15) >> 4;
  354.   word_aligned <<= 1;
  355.  
  356.   /* width byte aligned */
  357.   width = (pic->img_w + 7) >> 3;
  358.  
  359.   /* allocate memory for the picture */
  360.   free(pic->addr);
  361.   size = (long) word_aligned * pic->img_h * pic->planes;
  362.  
  363.   /* check for header validity & malloc long... */
  364.   if (pic->length > 7 && pic->planes < 33 && pic->img_w > 0 && pic->img_h > 0)
  365.     pic->addr = (char *) lalloc(size);
  366.   else
  367.   {
  368.     error = ERR_HEADER;
  369.     goto end_depack;
  370.   }
  371.  
  372.   /* if allocation succeded, proceed with depacking */
  373.   if(pic->addr == NULL)
  374.   {
  375.     error = ERR_ALLOC;
  376.     goto end_depack;
  377.   }
  378.   else
  379.   {
  380.     patt_len = pic->pat_len;
  381.     endline = buf + width;
  382.  
  383.     /* jump over the header and possible (XIMG) info */
  384.     fseek(fp, (long) pic->length * 2, SEEK_SET);
  385.  
  386.     /* depack whole img */
  387.     for(line = 0; line < pic->img_h; line += scan_repeat)
  388.     {
  389.       scan_repeat = 1;
  390.  
  391.       /* depack one scan line */
  392.       for(plane = 0; plane < pic->planes; plane ++)
  393.       {
  394.     to = buf;
  395.  
  396.     /* depack one line in one bitplane */
  397.     do
  398.     {
  399.       opcode = fgetc(fp);
  400.       switch(opcode)
  401.       {
  402.         /* pattern or scan repeat */
  403.         case 0:
  404.  
  405.           patt_repeat = fgetc(fp);
  406.           /* repeat a pattern */
  407.           if(patt_repeat)
  408.           {
  409.         /* read pattern */
  410.         for(b = 0; b < patt_len; b ++)
  411.           pattern[b] = fgetc(fp);
  412.  
  413.         /* copy pattern */
  414.         for(a = 0; a < patt_repeat; a ++)
  415.         {
  416.           /* in case it's odd amount... */
  417.           for(b = 0; b < patt_len; b ++)
  418.             *(to ++) = pattern[b];
  419.         }
  420.           }
  421.  
  422.           /* repeat a line */
  423.           else
  424.           {
  425.         if(fgetc(fp) == 0xFF)
  426.           scan_repeat = fgetc(fp);
  427.         else
  428.         {
  429.           error = ERR_DEPACK;
  430.           goto end_depack;
  431.         }
  432.           }
  433.           break;
  434.  
  435.         /* repeat 'as is' */
  436.         case 0x80:
  437.           byte_repeat = fgetc(fp);
  438.           for(; byte_repeat > 0; byte_repeat --)
  439.         *(to ++) = fgetc(fp);
  440.           break;
  441.  
  442.         /* repeat black or white */
  443.         default:
  444.           byte_repeat = opcode & 0x7F;
  445.           if(opcode & 0x80)
  446.         opcode = 0xFF;
  447.           else
  448.         opcode = 0x00;
  449.           for(; byte_repeat > 0; byte_repeat --)
  450.         *(to ++) = opcode;
  451.       }
  452.     }
  453.     while(to < endline);
  454.  
  455.     if(to == endline)
  456.     {
  457.       /* ensure that lines aren't repeated past the end of the img */
  458.       if(line + scan_repeat > pic->img_h)
  459.         scan_repeat = pic->img_h - line;
  460.  
  461.       /* calculate address of a current line in a current bitplane */
  462.       address = pic->addr  +
  463.           (long) line  * word_aligned +
  464.           (long) plane * word_aligned * pic->img_h;
  465.  
  466.       /* copy line to image buffer */
  467.       for(a = 0; a < scan_repeat; a ++)
  468.       {
  469.         memcpy(address, buf, width);
  470.         address += word_aligned;
  471.       }
  472.     }
  473.     else
  474.     {
  475.       error = ERR_DEPACK;
  476.       goto end_depack;
  477.     }
  478.       }
  479.     }
  480.   }
  481.  
  482.   end_depack:
  483.   fclose(fp);
  484.   return(error);
  485. }
  486.  
  487. /* show img on screen */
  488. void show_img(IMG_header *pic)
  489. {
  490.   short buttons = 0, key, x1 = 0, y1 = 0, x2 = 0, y2 = 0,
  491.     mx, my, xx, yy, cen_x, cen_y, redraw = TRUE, pxyarray[8], colors;
  492.   MFDB image, screen;
  493.  
  494.   /* Screen and Image VDI Memory Form Definitions. */
  495.   screen.fd_addr   = 0;
  496.   image.fd_addr    = pic->addr;                 /* address      */
  497.   image.fd_w       = pic->img_w;                /* width        */
  498.   image.fd_wdwidth = (pic->img_w + 15) >> 4;    /* (words)      */
  499.   image.fd_h       = pic->img_h;                /* height       */
  500.   image.fd_stand   = 0;                         /* raster format = device */
  501.   image.fd_nplanes = pic->planes;               /* bitplanes    */
  502.  
  503.   /* pic size on screen */
  504.   xx = min(wg_w, pic->img_w);
  505.   yy = min(wg_h, pic->img_h);
  506.  
  507.   /* for centering pic on screen */
  508.   cen_x = ((wg_w - xx) >> 1) + wg_x;
  509.   cen_y = ((wg_h - yy) >> 1) + wg_y;
  510.  
  511.   /* convert image to the current screen format if necessary */
  512.   if(!(transform_img(&image, pic->palette)))
  513.   {
  514.     return(FALSE);
  515.   }
  516.  
  517.   /* if a color image with a RGB palette and color resolution */
  518.   colors = (pic->palette != NULL && screen_planes > 1 && screen_planes < 9);
  519.   if(colors)
  520.     set_colors(pic->palette, min(screen_colors, pic->planes));
  521.  
  522.   do
  523.   {
  524.     /* get mouse position */
  525.     graf_mkstate(&mx, &my, &buttons, &key);
  526.  
  527.     /* calculate new image place */
  528.     x1 = (long) mx * (image.fd_w - xx) / screen_w;
  529.     y1 = (long) my * (image.fd_h - yy) / screen_h;
  530.  
  531.     /* fit co-ordinates onto screen */
  532.     x1 = min(x1, pic->img_w - xx);
  533.     y1 = min(y1, pic->img_h - yy);
  534.     x1 = max(0, x1);
  535.     y1 = max(0, y1);
  536.  
  537.     /* draw image if necessary */
  538.     if (redraw || x1 != x2 || y1 != y2)
  539.     {
  540.       /* put values into the co-ordinate array */
  541.       pxyarray[0] = x1;
  542.       pxyarray[1] = y1;
  543.       pxyarray[2] = x1 + xx - 1;
  544.       pxyarray[3] = y1 + yy - 1;
  545.       pxyarray[4] = cen_x;
  546.       pxyarray[5] = cen_y;
  547.       pxyarray[6] = cen_x + xx - 1;
  548.       pxyarray[7] = cen_y + yy - 1;
  549.  
  550.       /* throw onto screen */
  551.       vro_cpyfm(vdi_handle, S_ONLY, pxyarray, &image, &screen);
  552.  
  553.       x2 = x1; y2 = y1;
  554.       redraw = FALSE;
  555.     }
  556.   /* exit with right button */
  557.   }
  558.   while(!buttons);
  559.  
  560.   if(colors)
  561.     /* restore normal palette (already converted) */
  562.     set_colors(normal_palette, screen_planes);
  563.  
  564.   /* if image was converted to device format, free allcated memory */
  565.   if(image.fd_addr != pic->addr)
  566.     free(image.fd_addr);
  567.  
  568.   /* assure mouse button(s) off */
  569.   while(buttons)
  570.     graf_mkstate(&mx, &my, &buttons, &key);
  571. }
  572.  
  573. void set_colors(short *palette, int colors)
  574. {
  575.   int i, idx;
  576.  
  577.   /* set color palette */
  578.   colors = 1 << colors;
  579.   for(i = 0; i < colors; i++)
  580.   {
  581.     switch(screen_planes)
  582.     {
  583.       case 2:
  584.     idx = vdi2dev2[i];
  585.     break;
  586.       case 4:
  587.     idx = vdi2dev4[i];
  588.     break;
  589.       default:
  590.     idx = i;
  591.     }
  592.     vs_color(vdi_handle, i, palette + idx * 3);
  593.   }
  594. }
  595.  
  596. /* return FALSE if transformation was unsuccesful */
  597. int transform_img(MFDB *image, short *palette)
  598. {
  599.   int success;
  600.   long size;
  601.  
  602.   size = (long)(image->fd_wdwidth * image->fd_h);
  603.  
  604.   if(screen_planes == 1)
  605.   {
  606.     if(image->fd_nplanes > 1)
  607.     {
  608.       sprintf(notice, " Dithering %d bitplanes... ", image->fd_nplanes);
  609.       show_notice(TRUE);
  610.       success = dither((unsigned short **)&(image->fd_addr), size, (unsigned short)image->fd_wdwidth,
  611.                (unsigned short)image->fd_nplanes, palette);
  612.       show_notice(FALSE);
  613.       if(!success)
  614.       {
  615.     show_error(ERR_ALLOC);
  616.     return(FALSE);
  617.       }
  618.       image->fd_nplanes = 1;
  619.     }
  620.     return(TRUE);
  621.  
  622.   }
  623.   else
  624.   {
  625.     sprintf(notice, " Converting %d bitplanes... ", image->fd_nplanes);
  626.     show_notice(TRUE);
  627.  
  628.     /* Use vr_trfm(), which needs quite a lot memory. */
  629.     success = convert(image, size);
  630.     show_notice(FALSE);
  631.     if(success)
  632.     {
  633.       return(TRUE);
  634.     }
  635.     else
  636.       show_error(ERR_ALLOC);
  637.   }
  638.   return(FALSE);
  639. }
  640.  
  641. /* dither bitplanes into an bw one */
  642. int dither(unsigned short **addr, long size, unsigned short width,
  643.        unsigned short planes, short *palette)
  644. {
  645.   long offset;
  646.   register unsigned short  *plane, i, bit, color, result, *mat;
  647.   unsigned short  first_plane[32], *last,
  648.           col_max = 0, col_min = 0,
  649.           count = 0, row = 0, modulo = 0,
  650.           *idx, *end, *new_addr, *new,
  651.           intensity[256];
  652.  
  653.   /* ordered dithering matrix */
  654.   static unsigned short matrix[16][16] =
  655.    {{0x00, 0xc0, 0x30, 0xf0, 0x0c, 0xcc, 0x3c, 0xfc,
  656.      0x03, 0xc3, 0x33, 0xf3, 0x0f, 0xcf, 0x3f, 0xff},
  657.     {0x80, 0x40, 0xb0, 0x70, 0x8c, 0x4c, 0xbc, 0x7c,
  658.      0x83, 0x43, 0xb3, 0x73, 0x8f, 0x4f, 0xbf, 0x7f},
  659.     {0x20, 0xe0, 0x10, 0xd0, 0x2c, 0xec, 0x1c, 0xdc,
  660.      0x23, 0xe3, 0x13, 0xd3, 0x2f, 0xef, 0x1f, 0xdf},
  661.     {0xa0, 0x60, 0x90, 0x50, 0xac, 0x6c, 0x9c, 0x5c,
  662.      0xa3, 0x63, 0x93, 0x53, 0xaf, 0x6f, 0x9f, 0x5f},
  663.     {0x08, 0xc8, 0x38, 0xf8, 0x04, 0xc4, 0x34, 0xf4,
  664.      0x0b, 0xcb, 0x3b, 0xfb, 0x07, 0xc7, 0x37, 0xf7},
  665.     {0x88, 0x48, 0xb8, 0x78, 0x84, 0x44, 0xb4, 0x74,
  666.      0x8b, 0x4b, 0xbb, 0x7b, 0x87, 0x47, 0xb7, 0x77},
  667.     {0x28, 0xe8, 0x18, 0xd8, 0x24, 0xe4, 0x14, 0xd4,
  668.      0x2b, 0xeb, 0x1b, 0xdb, 0x27, 0xe7, 0x17, 0xd7},
  669.     {0xa8, 0x68, 0x98, 0x58, 0xa4, 0x64, 0x94, 0x54,
  670.      0xab, 0x6b, 0x9b, 0x5b, 0xa7, 0x67, 0x97, 0x57},
  671.     {0x02, 0xc2, 0x32, 0xf2, 0x0e, 0xce, 0x3e, 0xfe,
  672.      0x01, 0xc1, 0x31, 0xf1, 0x0d, 0xcd, 0x3d, 0xfd},
  673.     {0x82, 0x42, 0xb2, 0x72, 0x8e, 0x4e, 0xbe, 0x7e,
  674.      0x81, 0x41, 0xb1, 0x71, 0x8d, 0x4d, 0xbd, 0x7d},
  675.     {0x22, 0xe2, 0x12, 0xd2, 0x2e, 0xee, 0x1e, 0xde,
  676.      0x21, 0xe1, 0x11, 0xd1, 0x2d, 0xed, 0x1d, 0xdd},
  677.     {0xa2, 0x62, 0x92, 0x52, 0xae, 0x6e, 0x9e, 0x5e,
  678.      0xa1, 0x61, 0x91, 0x51, 0xad, 0x6d, 0x9d, 0x5d},
  679.     {0x0a, 0xca, 0x3a, 0xfa, 0x06, 0xc6, 0x36, 0xf6,
  680.      0x09, 0xc9, 0x39, 0xf9, 0x05, 0xc5, 0x35, 0xf5},
  681.     {0x8a, 0x4a, 0xba, 0x7a, 0x86, 0x46, 0xb6, 0x76,
  682.      0x89, 0x49, 0xb9, 0x79, 0x85, 0x45, 0xb5, 0x75},
  683.     {0x2a, 0xea, 0x1a, 0xda, 0x26, 0xe6, 0x16, 0xd6,
  684.      0x29, 0xe9, 0x19, 0xd9, 0x25, 0xe5, 0x15, 0xd5},
  685.     {0xaa, 0x6a, 0x9a, 0x5a, 0xa6, 0x66, 0x96, 0x56,
  686.      0xa9, 0x69, 0x99, 0x59, 0xa5, 0x65, 0x95, 0x55}};
  687.  
  688.   /* allocate space for the new (dithered) bitmap */
  689.   if((new_addr = (unsigned short *) lalloc(size * sizeof(**addr))) == NULL)
  690.     return(FALSE);
  691.  
  692.   last = first_plane + planes - 1;
  693.   planes = (1 << planes);
  694.  
  695.   /* scan palette */
  696.   if(planes <= 256)
  697.   {
  698.     for(i = 0; i < planes; i ++)
  699.     {
  700.       intensity[i] = 0;
  701.       /* add register values together to get the grey level */
  702.       for(bit = 0; bit < 3; bit ++)
  703.       {
  704.     intensity[i] += *(palette + 3 * i + bit);
  705.       }
  706.       col_min = min(col_min, intensity[i]);
  707.       col_max = max(col_max, intensity[i]);
  708.     }
  709.     /* scale color values to 0 - 255 range */
  710.     for(i = 0; i < planes; i ++)
  711.     {
  712.       intensity[i] = (long)(intensity[i] - col_min) * 255 / (col_max - col_min);
  713.     }
  714.   }
  715.  
  716.   /* destination pointer */
  717.   new = new_addr;
  718.   /* NOTICE: *addr + size = *addr + sizeof(**addr) * size!!! */
  719.   end = *addr + size;
  720.  
  721.   /* remake first bitplane */
  722.   planes >>= 1;
  723.   for(idx = *addr; idx < end; idx ++)
  724.   {
  725.     /* go through all bitplanes */
  726.     plane = first_plane;
  727.     offset = 0;
  728.     for(i = planes; i > 0; i >>= 1)
  729.     {
  730.       /* get one word from a bitplane */
  731.       *(plane ++) = (short) *(idx + offset);
  732.       offset += size;
  733.     }
  734.  
  735.     /* get row's modulo into dither matrix */
  736.     if(++ count == width)
  737.     {
  738.       count = 0;
  739.       row ++;
  740.       modulo = row % 16;
  741.     }
  742.  
  743.     result = 0;
  744.     mat = matrix[modulo];
  745.  
  746.     /* go through one word on all bitplanes */
  747.     for(bit = 0x8000; bit > 0; bit >>= 1)
  748.     {
  749.       color = 0;
  750.       plane = last;
  751.  
  752.       /* planar->chunky */
  753.       for(i = planes; i > 0; i >>= 1)
  754.     if((*(plane --) & bit))
  755.       color |= i;
  756.  
  757.       /* set bit in resulting bitplane if its' intensity demands it */
  758.       if(intensity[color] < *(mat ++))
  759.     result |= bit;
  760.     }
  761.     *(new ++) = result;
  762.   }
  763.   *addr = new_addr;
  764.   return(TRUE);
  765. }
  766.  
  767. /* convert image using the standard vr_trfm() */
  768. int convert(MFDB *image, long size)
  769. {
  770.   int i, plane, planes, line_size, width;
  771.   char *line_addr, *buf_addr, *new_addr;
  772.   char *image_addr, *screen_addr;
  773.   MFDB  screen, tmp;
  774.  
  775.   /* convert size from words to bytes */
  776.   size <<= 1;
  777.  
  778.   /* memory for the device raster */
  779.   if((new_addr = (char *) lalloc(size * screen_planes)) == NULL)
  780.     return(FALSE);
  781.  
  782.   /* initialize MFDBs */
  783.   tmp = *image;
  784.   tmp.fd_h = 1;
  785.   tmp.fd_nplanes = screen_planes;
  786.   tmp.fd_addr = buf;
  787.   tmp.fd_stand = 1;             /* standard format */
  788.   screen = tmp;
  789.   screen_addr = new_addr;
  790.   screen.fd_stand = 0;          /* device format */
  791.   image_addr = (char *)image->fd_addr;
  792.  
  793.   /* initialize some variables and zero temp. line buffer */
  794.   planes = min(image->fd_nplanes, screen_planes);
  795.   width = (tmp.fd_wdwidth << 1);
  796.   line_size = screen_planes * width;
  797.   for(i = 0; i < line_size; i ++)
  798.     buf[i] = 0;
  799.  
  800.   /* convert image */
  801.   for(i = 0; i < image->fd_h; i ++)
  802.   {
  803.     line_addr = image_addr + width * i;
  804.     buf_addr = buf;
  805.     if(planes > 1)
  806.     {
  807.       /* cut / pad color planes into temp buf */
  808.       for(plane = 0; plane < planes; plane ++)
  809.       {
  810.     memcpy(buf_addr, line_addr, width);
  811.     line_addr += size;
  812.     buf_addr += width;
  813.       }
  814.     }
  815.     else
  816.     {
  817.       /* fill temp line bitplanes with a b&w line */
  818.       for(plane = 0; plane < screen_planes; plane ++)
  819.       {
  820.     memcpy(buf_addr, line_addr, width);
  821.     buf_addr += width;
  822.       }
  823.     }
  824.     /* convert image line in temp into current device raster format */
  825.     screen.fd_addr = screen_addr;
  826.     vr_trnfm(vdi_handle, &tmp, &screen);
  827.     screen_addr += line_size;
  828.   }
  829.   /* change image description */
  830.   image->fd_stand = 0;          /* device format */
  831.   image->fd_addr = new_addr;
  832.   image->fd_nplanes = screen_planes;
  833.   return(TRUE);
  834. }